home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / src / actions.c next >
Encoding:
C/C++ Source or Header  |  2000-03-23  |  46.0 KB  |  1,820 lines

  1. /* action.c- misc. window commands (miniaturize, hide etc.)
  2.  * 
  3.  *  Window Maker window manager
  4.  * 
  5.  *  Copyright (c) 1997, 1998, 1999 Alfredo K. Kojima
  6.  *  Copyright (c) 1998       Dan Pascu
  7.  * 
  8.  *  This program is free software; you can redistribute it and/or modify
  9.  *  it under the terms of the GNU General Public License as published by
  10.  *  the Free Software Foundation; either version 2 of the License, or
  11.  *  (at your option) any later version.
  12.  *
  13.  *  This program is distributed in the hope that it will be useful,
  14.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  *  GNU General Public License for more details.
  17.  *
  18.  *  You should have received a copy of the GNU General Public License
  19.  *  along with this program; if not, write to the Free Software
  20.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
  21.  *  USA.
  22.  */
  23.  
  24. #include "wconfig.h"
  25.  
  26.  
  27. #include <X11/Xlib.h>
  28. #include <X11/Xutil.h>
  29. #include <stdlib.h>
  30. #include <stdio.h>
  31. #include <unistd.h>
  32. #include <math.h>
  33. #include <time.h>
  34.  
  35. #include "WindowMaker.h"
  36. #include "wcore.h"
  37. #include "framewin.h"
  38. #include "window.h"
  39. #include "client.h"
  40. #include "icon.h"
  41. #include "funcs.h"
  42. #include "application.h"
  43. #include "actions.h"
  44. #include "stacking.h"
  45. #include "appicon.h"
  46. #include "dock.h"
  47. #include "appmenu.h"
  48. #include "winspector.h"
  49. #include "workspace.h"
  50.  
  51. #ifdef GNOME_STUFF
  52. # include "gnome.h"
  53. #endif
  54. #ifdef KWM_HINTS
  55. # include "kwm.h"
  56. #endif
  57.  
  58. #ifdef WMSOUND
  59. #include "wmsound.h"
  60. #endif
  61.  
  62.  
  63. /****** Global Variables ******/
  64. extern Time LastTimestamp;
  65. extern Time LastFocusChange;
  66.  
  67. extern Cursor wCursor[WCUR_LAST];
  68.  
  69. extern WPreferences wPreferences;
  70.  
  71. extern Atom _XA_WM_TAKE_FOCUS;
  72.  
  73.  
  74. /******* Local Variables *******/
  75. static struct {
  76.     int steps;
  77.     int delay;
  78. } shadePars[5] = {
  79.     {SHADE_STEPS_UF, SHADE_DELAY_UF},
  80.     {SHADE_STEPS_F, SHADE_DELAY_F},
  81.     {SHADE_STEPS_M, SHADE_DELAY_M},
  82.     {SHADE_STEPS_S, SHADE_DELAY_S},
  83.     {SHADE_STEPS_U, SHADE_DELAY_U}};
  84.  
  85. #define SHADE_STEPS    shadePars[(int)wPreferences.shade_speed].steps
  86. #define SHADE_DELAY    shadePars[(int)wPreferences.shade_speed].delay
  87.  
  88.  
  89. static int ignoreTimestamp=0;
  90.  
  91.  
  92. #ifdef ANIMATIONS
  93. static void
  94. processEvents(int event_count)
  95. {
  96.     XEvent event;
  97.  
  98.     /*
  99.      * This is a hack. When animations are enabled, processing of 
  100.      * events ocurred during a animation are delayed until it's end.
  101.      * Calls that consider the TimeStamp, like XSetInputFocus(), will
  102.      * fail because the TimeStamp is too old. Then, for example, if
  103.      * the user changes window focus while a miniaturize animation is
  104.      * in course, the window will not get focus properly after the end
  105.      * of the animation. This tries to workaround it by passing CurrentTime
  106.      * as the TimeStamp for XSetInputFocus() for all events ocurred during
  107.      * the animation.
  108.      */
  109.     ignoreTimestamp=1;
  110.     while (XPending(dpy) && event_count--) {
  111.     WMNextEvent(dpy, &event);
  112.     WMHandleEvent(&event);
  113.     }
  114.     ignoreTimestamp=0;
  115. }
  116. #endif /* ANIMATIONS */
  117.  
  118.  
  119.  
  120. /*
  121.  *---------------------------------------------------------------------- 
  122.  * wSetFocusTo--
  123.  *     Changes the window focus to the one passed as argument.
  124.  * If the window to focus is not already focused, it will be brought
  125.  * to the head of the list of windows. Previously focused window is
  126.  * unfocused. 
  127.  * 
  128.  * Side effects:
  129.  *     Window list may be reordered and the window focus is changed.
  130.  * 
  131.  *---------------------------------------------------------------------- 
  132.  */
  133. void
  134. wSetFocusTo(WScreen *scr, WWindow  *wwin)
  135. {
  136.     static WScreen *old_scr=NULL;
  137.  
  138.     WWindow *old_focused;
  139.     WWindow *focused=scr->focused_window;
  140.     int timestamp=LastTimestamp;
  141.     WApplication *oapp=NULL, *napp=NULL;
  142.     int wasfocused;
  143.  
  144.     if (!old_scr)
  145.       old_scr=scr;
  146.     old_focused=old_scr->focused_window;
  147.  
  148.     LastFocusChange = timestamp;
  149.  
  150. /*
  151.  * This is a hack, because XSetInputFocus() should have a proper
  152.  * timestamp instead of CurrentTime but it seems that some times
  153.  * clients will not receive focus properly that way.
  154.     if (ignoreTimestamp)
  155. */
  156.       timestamp = CurrentTime;
  157.  
  158.     if (old_focused)
  159.     oapp = wApplicationOf(old_focused->main_window);
  160.  
  161.     if (wwin == NULL) {
  162.     XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
  163.     if (old_focused && !old_focused->flags.is_gnustep) {
  164.         wWindowUnfocus(old_focused);
  165.     }
  166.     if (oapp) {
  167.         wAppMenuUnmap(oapp->menu);
  168. #ifdef NEWAPPICON
  169.         wApplicationDeactivate(oapp);
  170. #endif
  171.     }
  172. #ifdef KWM_HINTS
  173.     wKWMUpdateActiveWindowHint(scr);
  174.     wKWMSendEventMessage(NULL, WKWMFocusWindow);
  175. #endif
  176.     return;
  177.     } else if (old_scr != scr && old_focused && !old_focused->flags.is_gnustep) {
  178.         wWindowUnfocus(old_focused);
  179.     }
  180.  
  181.     wasfocused = wwin->flags.focused;
  182.     napp = wApplicationOf(wwin->main_window);
  183.  
  184.     /* remember last workspace where the app has been */
  185.     if (napp) 
  186.     napp->last_workspace = wwin->screen_ptr->current_workspace;
  187.  
  188.     if (wwin->flags.mapped && !WFLAGP(wwin, no_focusable)) {
  189.     /* install colormap if colormap mode is lock mode */
  190.     if (wPreferences.colormap_mode==WKF_CLICK)
  191.         wColormapInstallForWindow(scr, wwin);
  192.  
  193.     /* set input focus */
  194.     switch (wwin->focus_mode) {
  195.      case WFM_NO_INPUT:
  196.         XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
  197.         break;
  198.  
  199.      case WFM_PASSIVE:
  200.      case WFM_LOCALLY_ACTIVE:
  201.         XSetInputFocus(dpy, wwin->client_win, RevertToParent, timestamp);
  202.         break;
  203.  
  204.      case WFM_GLOBALLY_ACTIVE:
  205.         break;
  206.     }
  207.     XFlush(dpy);
  208.     if (wwin->protocols.TAKE_FOCUS) {
  209.         wClientSendProtocol(wwin, _XA_WM_TAKE_FOCUS, timestamp);
  210.     }
  211.     XSync(dpy, False);
  212.     } else {
  213.     XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp);
  214.     }
  215.     if (WFLAGP(wwin, no_focusable))
  216.     return;
  217.  
  218.     /* if this is not the focused window focus it */
  219.     if (focused!=wwin) {
  220.     /* change the focus window list order */
  221.     if (wwin->prev)
  222.       wwin->prev->next = wwin->next;
  223.  
  224.     if (wwin->next)
  225.       wwin->next->prev = wwin->prev;
  226.  
  227.     wwin->prev = focused;
  228.     focused->next = wwin;
  229.     wwin->next = NULL;
  230.     scr->focused_window = wwin;
  231.  
  232.     if (oapp && oapp != napp) {
  233.         wAppMenuUnmap(oapp->menu);
  234. #ifdef NEWAPPICON
  235.         wApplicationDeactivate(oapp);
  236. #endif
  237.     }
  238.     }
  239.  
  240.     if (!wwin->flags.is_gnustep)
  241.     wWindowFocus(wwin, focused);
  242.  
  243.     if (napp && !wasfocused) {
  244. #ifdef USER_MENU
  245.     wUserMenuRefreshInstances(napp->menu, wwin);
  246. #endif /* USER_MENU */
  247.  
  248.     if (wwin->flags.mapped)
  249.         wAppMenuMap(napp->menu, wwin);
  250. #ifdef NEWAPPICON
  251.     wApplicationActivate(napp);
  252. #endif
  253.     }
  254. #ifdef KWM_HINTS
  255.     wKWMUpdateActiveWindowHint(scr);
  256.     wKWMSendEventMessage(wwin, WKWMFocusWindow);
  257. #endif
  258.     XFlush(dpy);
  259.     old_scr=scr;
  260. }
  261.  
  262.  
  263. void
  264. wShadeWindow(WWindow  *wwin)
  265. {
  266.     time_t time0 = time(NULL);
  267. #ifdef ANIMATIONS
  268.     int y, s, w, h;
  269. #endif
  270.  
  271.     if (wwin->flags.shaded)
  272.     return;
  273.  
  274.     XLowerWindow(dpy, wwin->client_win);    
  275.  
  276. #ifdef WMSOUND
  277.     wSoundPlay(WMSOUND_SHADE);
  278. #endif
  279.  
  280. #ifdef ANIMATIONS
  281.     if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
  282.     && !wPreferences.no_animations) {
  283.     /* do the shading animation */
  284.     h = wwin->frame->core->height;
  285.         s = h/SHADE_STEPS;
  286.         if (s < 1) s=1;
  287.     w = wwin->frame->core->width;
  288.     y = wwin->frame->top_width;
  289.     while (h>wwin->frame->top_width+1) {
  290.         XMoveWindow(dpy, wwin->client_win, 0, y);
  291.         XResizeWindow(dpy, wwin->frame->core->window, w, h);
  292.         XFlush(dpy);
  293.  
  294.         if (time(NULL)-time0 > MAX_ANIMATION_TIME)
  295.         break;
  296.  
  297.             if (SHADE_DELAY > 0)
  298.                 wusleep(SHADE_DELAY*1000L);
  299.         h-=s;
  300.         y-=s;
  301.     }
  302.     XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
  303.     }
  304. #endif  /* ANIMATIONS */
  305.  
  306.     wwin->flags.skip_next_animation = 0;
  307.     wwin->flags.shaded = 1;
  308.     wwin->flags.mapped = 0;
  309.     /* prevent window withdrawal when getting UnmapNotify */
  310.     XSelectInput(dpy, wwin->client_win, 
  311.                  wwin->event_mask & ~StructureNotifyMask);
  312.     XUnmapWindow(dpy, wwin->client_win);
  313.     XSelectInput(dpy, wwin->client_win, wwin->event_mask);
  314.  
  315.     /* for the client it's just like iconification */
  316.     wFrameWindowResize(wwin->frame, wwin->frame->core->width,
  317.                wwin->frame->top_width - 1);
  318.     
  319.     wwin->client.y = wwin->frame_y - wwin->client.height 
  320.     + wwin->frame->top_width;
  321.     wWindowSynthConfigureNotify(wwin);
  322.  
  323.     /*
  324.     wClientSetState(wwin, IconicState, None);
  325.      */
  326.  
  327. #ifdef GNOME_STUFF
  328.     wGNOMEUpdateClientStateHint(wwin, False);
  329. #endif
  330. #ifdef KWM_HINTS
  331.     wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
  332.     wKWMSendEventMessage(wwin, WKWMChangedClient);
  333. #endif
  334.     /* update window list to reflect shaded state */
  335.     UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
  336.  
  337. #ifdef ANIMATIONS
  338.     if (!wwin->screen_ptr->flags.startup) {
  339.     /* Look at processEvents() for reason of this code. */
  340.         XSync(dpy, 0);
  341.         processEvents(XPending(dpy));
  342.     }
  343. #endif
  344. }
  345.  
  346.  
  347. void
  348. wUnshadeWindow(WWindow  *wwin)
  349. {
  350.     time_t time0 = time(NULL);
  351. #ifdef ANIMATIONS
  352.     int y, s, w, h;    
  353. #endif /* ANIMATIONS */
  354.  
  355.  
  356.     if (!wwin->flags.shaded)
  357.     return;
  358.     
  359.     wwin->flags.shaded = 0;
  360.     wwin->flags.mapped = 1;
  361.     XMapWindow(dpy, wwin->client_win);
  362.  
  363. #ifdef WMSOUND
  364.     wSoundPlay(WMSOUND_UNSHADE);
  365. #endif
  366.  
  367. #ifdef ANIMATIONS
  368.     if (!wPreferences.no_animations && !wwin->flags.skip_next_animation) {
  369.     /* do the shading animation */
  370.     h = wwin->frame->top_width + wwin->frame->bottom_width;
  371.     y = wwin->frame->top_width - wwin->client.height;
  372.         s = abs(y)/SHADE_STEPS;
  373.         if (s<1) s=1;
  374.     w = wwin->frame->core->width;
  375.     XMoveWindow(dpy, wwin->client_win, 0, y);
  376.     if (s>0) {
  377.         while (h < wwin->client.height + wwin->frame->top_width
  378.            + wwin->frame->bottom_width) {
  379.         XResizeWindow(dpy, wwin->frame->core->window, w, h);
  380.         XMoveWindow(dpy, wwin->client_win, 0, y);
  381.         XFlush(dpy);
  382.                 if (SHADE_DELAY > 0)
  383.                     wusleep(SHADE_DELAY*2000L/3);
  384.         h+=s;
  385.         y+=s;
  386.         
  387.         if (time(NULL)-time0 > MAX_ANIMATION_TIME)
  388.             break;
  389.         }
  390.     }
  391.     XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
  392.     }
  393. #endif /* ANIMATIONS */
  394.  
  395.     wwin->flags.skip_next_animation = 0;
  396.     wFrameWindowResize(wwin->frame, wwin->frame->core->width, 
  397.                wwin->frame->top_width + wwin->client.height
  398.                + wwin->frame->bottom_width);
  399.  
  400.     wwin->client.y = wwin->frame_y + wwin->frame->top_width;
  401.     wWindowSynthConfigureNotify(wwin);
  402.     
  403.     /*
  404.     wClientSetState(wwin, NormalState, None);
  405.      */
  406.     /* if the window is focused, set the focus again as it was disabled during
  407.      * shading */
  408.     if (wwin->flags.focused)
  409.     wSetFocusTo(wwin->screen_ptr, wwin);
  410.  
  411. #ifdef GNOME_STUFF
  412.     wGNOMEUpdateClientStateHint(wwin, False);
  413. #endif
  414. #ifdef KWM_HINTS
  415.     wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
  416.     wKWMSendEventMessage(wwin, WKWMChangedClient);
  417. #endif
  418.  
  419.     /* update window list to reflect unshaded state */
  420.     UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
  421.  
  422. }
  423.  
  424.  
  425. void
  426. wMaximizeWindow(WWindow *wwin, int directions)
  427. {
  428.     int new_width, new_height, new_x, new_y;
  429.     WArea usableArea = wwin->screen_ptr->totalUsableArea;
  430.  
  431.  
  432.     if (WFLAGP(wwin, no_resizable))
  433.     return;
  434.  
  435.     
  436.     if (WFLAGP(wwin, full_maximize)) {
  437.     usableArea.x1 = 0;
  438.     usableArea.y1 = 0;
  439.     usableArea.x2 = wwin->screen_ptr->scr_width;
  440.     usableArea.y2 = wwin->screen_ptr->scr_height;
  441.     }
  442.  
  443.     if (wwin->flags.shaded) {
  444.     wwin->flags.skip_next_animation = 1;
  445.     wUnshadeWindow(wwin);
  446.     }
  447.     wwin->flags.maximized = directions;
  448.     wwin->old_geometry.width = wwin->client.width;
  449.     wwin->old_geometry.height = wwin->client.height;
  450.     wwin->old_geometry.x = wwin->frame_x;
  451.     wwin->old_geometry.y = wwin->frame_y;
  452.  
  453. #ifdef KWM_HINTS
  454.     wKWMUpdateClientGeometryRestore(wwin);
  455. #endif
  456.  
  457.     if (directions & MAX_HORIZONTAL) {
  458.  
  459.     new_width = (usableArea.x2-usableArea.x1)-FRAME_BORDER_WIDTH*2;    
  460.     new_x = usableArea.x1;
  461.  
  462.     } else {
  463.  
  464.     new_x = wwin->frame_x;
  465.     new_width = wwin->frame->core->width;
  466.  
  467.     }
  468.  
  469.     if (directions & MAX_VERTICAL) {
  470.  
  471.     new_height = (usableArea.y2-usableArea.y1)-FRAME_BORDER_WIDTH*2;
  472.     new_y = usableArea.y1;
  473.     if (WFLAGP(wwin, full_maximize)) {
  474.         new_y -= wwin->frame->top_width;
  475.         new_height += wwin->frame->bottom_width - 1;
  476.     }
  477.     } else {
  478.     new_y = wwin->frame_y;
  479.     new_height = wwin->frame->core->height;
  480.     }
  481.  
  482.     if (!WFLAGP(wwin, full_maximize)) {
  483.     new_height -= wwin->frame->top_width+wwin->frame->bottom_width;
  484.     }
  485.  
  486.     wWindowConstrainSize(wwin, &new_width, &new_height);
  487.     wWindowConfigure(wwin, new_x, new_y, new_width, new_height);
  488.  
  489. #ifdef GNOME_STUFF
  490.     wGNOMEUpdateClientStateHint(wwin, False);
  491. #endif
  492. #ifdef KWM_HINTS
  493.     wKWMUpdateClientStateHint(wwin, KWMMaximizedFlag);
  494.     wKWMSendEventMessage(wwin, WKWMChangedClient);
  495. #endif
  496.  
  497. #ifdef WMSOUND
  498.     wSoundPlay(WMSOUND_MAXIMIZE);
  499. #endif
  500. }
  501.  
  502.  
  503. void
  504. wUnmaximizeWindow(WWindow *wwin)
  505. {
  506.     int restore_x, restore_y;
  507.  
  508.     if (!wwin->flags.maximized)
  509.     return;
  510.     
  511.     if (wwin->flags.shaded) {
  512.     wwin->flags.skip_next_animation = 1;
  513.     wUnshadeWindow(wwin);
  514.     }
  515.     restore_x = (wwin->flags.maximized & MAX_HORIZONTAL) ?
  516.         wwin->old_geometry.x : wwin->frame_x;
  517.     restore_y = (wwin->flags.maximized & MAX_VERTICAL) ?
  518.         wwin->old_geometry.y : wwin->frame_y;
  519.     wwin->flags.maximized = 0;
  520.     wWindowConfigure(wwin, restore_x, restore_y,
  521.              wwin->old_geometry.width, wwin->old_geometry.height);
  522.  
  523. #ifdef GNOME_STUFF
  524.     wGNOMEUpdateClientStateHint(wwin, False);
  525. #endif
  526. #ifdef KWM_HINTS
  527.     wKWMUpdateClientStateHint(wwin, KWMMaximizedFlag);
  528.     wKWMSendEventMessage(wwin, WKWMChangedClient);
  529. #endif
  530.  
  531. #ifdef WMSOUND
  532.     wSoundPlay(WMSOUND_UNMAXIMIZE);
  533. #endif
  534. }
  535.  
  536. #ifdef ANIMATIONS
  537. static void
  538. animateResizeFlip(WScreen *scr, int x, int y, int w, int h,
  539.                   int fx, int fy, int fw, int fh, int steps)
  540. {
  541. #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_F)
  542.     float cx, cy, cw, ch;
  543.     float xstep, ystep, wstep, hstep;
  544.     XPoint points[5]; 
  545.     float dx, dch, midy;
  546.     float angle, final_angle, delta;
  547.  
  548.     xstep = (float)(fx-x)/steps;
  549.     ystep = (float)(fy-y)/steps;
  550.     wstep = (float)(fw-w)/steps;
  551.     hstep = (float)(fh-h)/steps;
  552.      
  553.     cx = (float)x;
  554.     cy = (float)y;
  555.     cw = (float)w;
  556.     ch = (float)h;
  557.  
  558.     final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_F;
  559.     delta = (float)(final_angle/FRAMES);
  560.     for (angle=0;; angle+=delta) {
  561.         if (angle > final_angle)
  562.             angle = final_angle;
  563.  
  564.         dx = (cw/10) - ((cw/5) * sin(angle));
  565.         dch = (ch/2) * cos(angle);
  566.         midy = cy + (ch/2);
  567.  
  568.         points[0].x = cx + dx;      points[0].y = midy - dch;
  569.         points[1].x = cx + cw - dx; points[1].y = points[0].y;
  570.         points[2].x = cx + cw + dx; points[2].y = midy + dch;
  571.         points[3].x = cx - dx;      points[3].y = points[2].y;
  572.         points[4].x = points[0].x;  points[4].y = points[0].y;
  573.  
  574.         XGrabServer(dpy);
  575.         XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
  576.     XFlush(dpy);
  577. #if (MINIATURIZE_ANIMATION_DELAY_F > 0)
  578.         wusleep(MINIATURIZE_ANIMATION_DELAY_F);
  579. #endif
  580.  
  581.     XDrawLines(dpy,scr->root_win,scr->frame_gc,points, 5, CoordModeOrigin);
  582.     XUngrabServer(dpy);
  583.     cx+=xstep;
  584.     cy+=ystep;
  585.     cw+=wstep;
  586.     ch+=hstep;
  587.     if (angle >= final_angle)
  588.       break;
  589.  
  590.     }
  591.     XFlush(dpy);
  592. }
  593. #undef FRAMES
  594.  
  595.  
  596. static void 
  597. animateResizeTwist(WScreen *scr, int x, int y, int w, int h,
  598.                    int fx, int fy, int fw, int fh, int steps)
  599. {
  600. #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_T)
  601.     float cx, cy, cw, ch;
  602.     float xstep, ystep, wstep, hstep;
  603.     XPoint points[5]; 
  604.     float angle, final_angle, a, d, delta;
  605.  
  606.     x += w/2;
  607.     y += h/2;
  608.     fx += fw/2;
  609.     fy += fh/2;
  610.  
  611.     xstep = (float)(fx-x)/steps;
  612.     ystep = (float)(fy-y)/steps;
  613.     wstep = (float)(fw-w)/steps;
  614.     hstep = (float)(fh-h)/steps;
  615.      
  616.     cx = (float)x;
  617.     cy = (float)y;
  618.     cw = (float)w;
  619.     ch = (float)h;
  620.  
  621.     final_angle = 2*WM_PI*MINIATURIZE_ANIMATION_TWIST_T;
  622.     delta =  (float)(final_angle/FRAMES);
  623.     for (angle=0;; angle+=delta) {
  624.         if (angle > final_angle)
  625.             angle = final_angle;
  626.  
  627.         a = atan(ch/cw);
  628.         d = sqrt((cw/2)*(cw/2)+(ch/2)*(ch/2));
  629.  
  630.         points[0].x = cx+cos(angle-a)*d;
  631.         points[0].y = cy+sin(angle-a)*d;
  632.         points[1].x = cx+cos(angle+a)*d;
  633.         points[1].y = cy+sin(angle+a)*d;
  634.         points[2].x = cx+cos(angle-a+WM_PI)*d;
  635.         points[2].y = cy+sin(angle-a+WM_PI)*d;
  636.         points[3].x = cx+cos(angle+a+WM_PI)*d;
  637.         points[3].y = cy+sin(angle+a+WM_PI)*d;
  638.         points[4].x = cx+cos(angle-a)*d;
  639.         points[4].y = cy+sin(angle-a)*d;
  640.         XGrabServer(dpy);
  641.         XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
  642.     XFlush(dpy);
  643. #if (MINIATURIZE_ANIMATION_DELAY_T > 0)
  644.         wusleep(MINIATURIZE_ANIMATION_DELAY_T);
  645. #endif
  646.  
  647.         XDrawLines(dpy, scr->root_win, scr->frame_gc, points, 5, CoordModeOrigin);
  648.     XUngrabServer(dpy);
  649.     cx+=xstep;
  650.     cy+=ystep;
  651.     cw+=wstep;
  652.     ch+=hstep;
  653.     if (angle >= final_angle)
  654.       break;
  655.  
  656.     }
  657.     XFlush(dpy);
  658. }
  659. #undef FRAMES
  660.  
  661.  
  662. static void 
  663. animateResizeZoom(WScreen *scr, int x, int y, int w, int h,
  664.                   int fx, int fy, int fw, int fh, int steps)
  665. {
  666. #define FRAMES (MINIATURIZE_ANIMATION_FRAMES_Z)
  667.     float cx[FRAMES], cy[FRAMES], cw[FRAMES], ch[FRAMES];
  668.     float xstep, ystep, wstep, hstep;
  669.     int i, j;
  670.  
  671.     xstep = (float)(fx-x)/steps;
  672.     ystep = (float)(fy-y)/steps;
  673.     wstep = (float)(fw-w)/steps;
  674.     hstep = (float)(fh-h)/steps;
  675.     
  676.     for (j=0; j<FRAMES; j++) {
  677.     cx[j] = (float)x;
  678.     cy[j] = (float)y;
  679.     cw[j] = (float)w;
  680.     ch[j] = (float)h;
  681.     }
  682.     XGrabServer(dpy);
  683.     for (i=0; i<steps; i++) {
  684.     for (j=0; j<FRAMES; j++) {
  685.         XDrawRectangle(dpy, scr->root_win, scr->frame_gc, 
  686.                (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
  687.     }
  688.     XFlush(dpy);
  689. #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
  690.         wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
  691. #endif
  692.     for (j=0; j<FRAMES; j++) {
  693.         XDrawRectangle(dpy, scr->root_win, scr->frame_gc, 
  694.                (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
  695.         if (j<FRAMES-1) {
  696.         cx[j]=cx[j+1];
  697.         cy[j]=cy[j+1];
  698.         cw[j]=cw[j+1];
  699.         ch[j]=ch[j+1];
  700.         } else {
  701.         cx[j]+=xstep;
  702.         cy[j]+=ystep;
  703.         cw[j]+=wstep;
  704.         ch[j]+=hstep;
  705.         }
  706.     }
  707.     }
  708.  
  709.     for (j=0; j<FRAMES; j++) {
  710.     XDrawRectangle(dpy, scr->root_win, scr->frame_gc, 
  711.                (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
  712.     }
  713.     XFlush(dpy);
  714. #if (MINIATURIZE_ANIMATION_DELAY_Z > 0)
  715.     wusleep(MINIATURIZE_ANIMATION_DELAY_Z);
  716. #endif
  717.     for (j=0; j<FRAMES; j++) {
  718.     XDrawRectangle(dpy, scr->root_win, scr->frame_gc, 
  719.                (int)cx[j], (int)cy[j], (int)cw[j], (int)ch[j]);
  720.     }
  721.     
  722.     XUngrabServer(dpy);
  723. }
  724. #undef FRAMES
  725.  
  726.  
  727. static void 
  728. animateResize(WScreen *scr, int x, int y, int w, int h, 
  729.           int fx, int fy, int fw, int fh, int hiding)
  730. {
  731.     int style = wPreferences.iconification_style; /* Catch the value */
  732.     int steps, k;
  733.  
  734.     if (style == WIS_NONE)
  735.         return;
  736.  
  737.     if (style == WIS_RANDOM) {
  738.     style = rand()%3;
  739.     }
  740.  
  741.     k = (hiding ? 2 : 3);
  742.     switch(style) {
  743.     case WIS_TWIST:
  744.         steps = (MINIATURIZE_ANIMATION_STEPS_T * k)/3;
  745.         if (steps>0)
  746.             animateResizeTwist(scr, x, y, w, h, fx, fy, fw, fh, steps);
  747.         break;
  748.     case WIS_FLIP:
  749.         steps = (MINIATURIZE_ANIMATION_STEPS_F * k)/3;
  750.         if (steps>0)
  751.             animateResizeFlip(scr, x, y, w, h, fx, fy, fw, fh, steps);
  752.         break;
  753.     case WIS_ZOOM:
  754.     default:
  755.         steps = (MINIATURIZE_ANIMATION_STEPS_Z * k)/3;
  756.         if (steps>0)
  757.             animateResizeZoom(scr, x, y, w, h, fx, fy, fw, fh, steps);
  758.         break;
  759.     }
  760. }
  761. #endif /* ANIMATIONS */
  762.  
  763.  
  764. static void
  765. flushExpose()
  766. {
  767.     XEvent tmpev;
  768.     
  769.     while (XCheckTypedEvent(dpy, Expose, &tmpev))
  770.     WMHandleEvent(&tmpev);
  771.     XSync(dpy, 0);
  772. }
  773.  
  774. static void
  775. unmapTransientsFor(WWindow *wwin)
  776. {
  777.     WWindow *tmp;
  778.     
  779.  
  780.     tmp = wwin->screen_ptr->focused_window;
  781.     while (tmp) {
  782.     /* unmap the transients for this transient */
  783.     if (tmp!=wwin && tmp->transient_for == wwin->client_win
  784.         && (tmp->flags.mapped || wwin->screen_ptr->flags.startup
  785.         || tmp->flags.shaded)) {
  786.         unmapTransientsFor(tmp);
  787.         tmp->flags.miniaturized = 1;
  788.         if (!tmp->flags.shaded) {
  789.         wWindowUnmap(tmp);
  790.         } else {
  791.         XUnmapWindow(dpy, tmp->frame->core->window);
  792.         }
  793.         /*
  794.         if (!tmp->flags.shaded)
  795.          */
  796.         wClientSetState(tmp, IconicState, None);
  797. #ifdef KWM_HINTS
  798.         wKWMUpdateClientStateHint(tmp, KWMIconifiedFlag);
  799.         wKWMSendEventMessage(tmp, WKWMRemoveWindow);
  800.         tmp->flags.kwm_hidden_for_modules = 1;
  801. #endif
  802.  
  803.         UpdateSwitchMenu(wwin->screen_ptr, tmp, ACTION_CHANGE_STATE);
  804.  
  805.     }
  806.     tmp = tmp->prev;
  807.     }
  808. }
  809.  
  810.  
  811. static void
  812. mapTransientsFor(WWindow *wwin)
  813. {
  814.     WWindow *tmp;
  815.  
  816.     tmp = wwin->screen_ptr->focused_window;
  817.     while (tmp) {
  818.     /* recursively map the transients for this transient */
  819.     if (tmp!=wwin && tmp->transient_for == wwin->client_win
  820.         && /*!tmp->flags.mapped*/ tmp->flags.miniaturized 
  821.         && tmp->icon==NULL) {
  822.         mapTransientsFor(tmp);
  823.         tmp->flags.miniaturized = 0;
  824.         if (!tmp->flags.shaded) {
  825.         wWindowMap(tmp);
  826.         } else {
  827.         XMapWindow(dpy, tmp->frame->core->window);
  828.         }
  829.          tmp->flags.semi_focused = 0;
  830.         /*
  831.         if (!tmp->flags.shaded)
  832.          */
  833.         wClientSetState(tmp, NormalState, None);
  834. #ifdef KWM_HINTS
  835.         wKWMUpdateClientStateHint(tmp, KWMIconifiedFlag);
  836.         if (tmp->flags.kwm_hidden_for_modules) {
  837.         wKWMSendEventMessage(tmp, WKWMAddWindow);
  838.         tmp->flags.kwm_hidden_for_modules = 0;
  839.         }
  840. #endif
  841.  
  842.         UpdateSwitchMenu(wwin->screen_ptr, tmp, ACTION_CHANGE_STATE);
  843.  
  844.     }
  845.     tmp = tmp->prev;
  846.     }
  847. }
  848.  
  849. #if 0
  850. static void
  851. setupIconGrabs(WIcon *icon)
  852. {
  853.     /* setup passive grabs on the icon */
  854.     XGrabButton(dpy, Button1, AnyModifier, icon->core->window, True,
  855.         ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
  856.     XGrabButton(dpy, Button2, AnyModifier, icon->core->window, True,
  857.         ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
  858.     XGrabButton(dpy, Button3, AnyModifier, icon->core->window, True,
  859.         ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
  860.     XSync(dpy, 0);
  861. }
  862. #endif
  863.  
  864. static WWindow*
  865. recursiveTransientFor(WWindow *wwin)
  866. {
  867.     int i;
  868.  
  869.     if (!wwin)
  870.     return None;
  871.  
  872.     /* hackish way to detect transient_for cycle */ 
  873.     i = wwin->screen_ptr->window_count+1;
  874.  
  875.     while (wwin && wwin->transient_for != None && i>0) {
  876.     wwin = wWindowFor(wwin->transient_for);
  877.     i--;
  878.     }
  879.     if (i==0 && wwin) {
  880.     wwarning("%s has a severely broken WM_TRANSIENT_FOR hint.",
  881.          wwin->frame->title);
  882.     return NULL;
  883.     }
  884.  
  885.     return wwin;
  886. }
  887.  
  888. #if 0
  889. static void
  890. removeIconGrabs(WIcon *icon)
  891. {
  892.     /* remove passive grabs on the icon */
  893.     XUngrabButton(dpy, Button1, AnyModifier, icon->core->window);
  894.     XUngrabButton(dpy, Button2, AnyModifier, icon->core->window);
  895.     XUngrabButton(dpy, Button3, AnyModifier, icon->core->window);    
  896.     XSync(dpy, 0);
  897. }
  898. #endif
  899.  
  900.  
  901. void
  902. wIconifyWindow(WWindow *wwin)
  903. {
  904.     XWindowAttributes attribs;
  905.     int present;
  906.  
  907.  
  908.     if (!XGetWindowAttributes(dpy, wwin->client_win, &attribs)) {
  909.     /* the window doesn't exist anymore */
  910.     return;
  911.     }
  912.  
  913.     if (wwin->flags.miniaturized) {
  914.     return;
  915.     }
  916.  
  917.     
  918.     if (wwin->transient_for!=None) {
  919.     WWindow *owner = wWindowFor(wwin->transient_for);
  920.     
  921.     if (owner && owner->flags.miniaturized)
  922.         return;
  923.     }
  924.     
  925.     present = wwin->frame->workspace==wwin->screen_ptr->current_workspace;
  926.  
  927.     /* if the window is in another workspace, simplify process */
  928.     if (present) {
  929.     /* icon creation may take a while */
  930.     XGrabPointer(dpy, wwin->screen_ptr->root_win, False, 
  931.              ButtonMotionMask|ButtonReleaseMask, GrabModeAsync, 
  932.              GrabModeAsync, None, None, CurrentTime);
  933.     }
  934.  
  935.     if (!wPreferences.disable_miniwindows) {
  936.     if (!wwin->flags.icon_moved) {
  937.         PlaceIcon(wwin->screen_ptr, &wwin->icon_x, &wwin->icon_y);
  938.     }
  939.     wwin->icon = wIconCreate(wwin);
  940.  
  941.     wwin->icon->mapped = 1;
  942.     }
  943.  
  944.     wwin->flags.miniaturized = 1;
  945.     wwin->flags.mapped = 0;
  946.  
  947.     /* unmap transients */
  948.     
  949.     unmapTransientsFor(wwin);
  950.  
  951.     if (present) {
  952. #ifdef WMSOUND
  953.     wSoundPlay(WMSOUND_ICONIFY);
  954. #endif
  955.  
  956.     XUngrabPointer(dpy, CurrentTime);
  957.     wWindowUnmap(wwin);
  958.     /* let all Expose events arrive so that we can repaint
  959.      * something before the animation starts (and the server is grabbed) */
  960.     XSync(dpy, 0);
  961.  
  962.     if (wPreferences.disable_miniwindows)
  963.         wClientSetState(wwin, IconicState, None);
  964.     else
  965.         wClientSetState(wwin, IconicState, wwin->icon->icon_win);
  966.  
  967.     flushExpose();
  968. #ifdef ANIMATIONS
  969.     if (!wwin->screen_ptr->flags.startup && !wwin->flags.skip_next_animation
  970.         && !wPreferences.no_animations) {
  971.         int ix, iy, iw, ih;
  972.  
  973.         if (!wPreferences.disable_miniwindows) {
  974.         ix = wwin->icon_x;
  975.         iy = wwin->icon_y;
  976.         iw = wwin->icon->core->width;
  977.         ih = wwin->icon->core->height;
  978.         } else {
  979. #ifdef KWM_HINTS
  980.         WArea area;
  981.  
  982.         if (wKWMGetIconGeometry(wwin, &area)) {
  983.             ix = area.x1;
  984.             iy = area.y1;
  985.             iw = area.x2 - ix;
  986.             ih = area.y2 - iy;
  987.         } else
  988. #endif /* KWM_HINTS */
  989.         {
  990.             ix = 0;
  991.             iy = 0;
  992.             iw = wwin->screen_ptr->scr_width;
  993.             ih = wwin->screen_ptr->scr_height;
  994.         }
  995.         }
  996.         animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y, 
  997.               wwin->frame->core->width, wwin->frame->core->height,
  998.               ix, iy, iw, ih, False);
  999.     }
  1000. #endif
  1001.     }
  1002.     
  1003.     wwin->flags.skip_next_animation = 0;
  1004.  
  1005.     if (!wPreferences.disable_miniwindows) {
  1006.  
  1007.     if (wwin->screen_ptr->current_workspace==wwin->frame->workspace ||
  1008.         IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)
  1009.  
  1010.         XMapWindow(dpy, wwin->icon->core->window);
  1011.  
  1012.     AddToStackList(wwin->icon->core);
  1013.  
  1014.     wLowerFrame(wwin->icon->core);
  1015.     }
  1016.  
  1017.     if (present) {
  1018.     WWindow *owner = recursiveTransientFor(wwin->screen_ptr->focused_window);
  1019.  
  1020. /*
  1021.  * It doesn't seem to be working and causes button event hangup 
  1022.  * when deiconifying a transient window.
  1023.  setupIconGrabs(wwin->icon);
  1024.  */
  1025.     if ((wwin->flags.focused 
  1026.          || (owner && wwin->client_win == owner->client_win))
  1027.         && wPreferences.focus_mode==WKF_CLICK) {
  1028.         WWindow *tmp;
  1029.         
  1030.         tmp = wwin->prev;
  1031.         while (tmp) {
  1032.         if (!WFLAGP(tmp, no_focusable)
  1033.             && !(tmp->flags.hidden||tmp->flags.miniaturized)
  1034.             && (wwin->frame->workspace == tmp->frame->workspace))
  1035.             break;
  1036.         tmp = tmp->prev;
  1037.         }
  1038.         wSetFocusTo(wwin->screen_ptr, tmp);
  1039.     } else if (wPreferences.focus_mode!=WKF_CLICK) {
  1040.         wSetFocusTo(wwin->screen_ptr, NULL);
  1041.     }
  1042.  
  1043. #ifdef ANIMATIONS
  1044.     if (!wwin->screen_ptr->flags.startup) {
  1045.         Window clientwin = wwin->client_win;
  1046.  
  1047.         XSync(dpy, 0);
  1048.         processEvents(XPending(dpy));
  1049.         
  1050.         /* the window can disappear while doing the processEvents() */
  1051.         if (!wWindowFor(clientwin))
  1052.         return;
  1053.     }
  1054. #endif
  1055.     }
  1056.  
  1057.  
  1058.     if (wwin->flags.selected && !wPreferences.disable_miniwindows)
  1059.         wIconSelect(wwin->icon);
  1060.  
  1061. #ifdef GNOME_STUFF
  1062.     wGNOMEUpdateClientStateHint(wwin, False);
  1063. #endif
  1064. #ifdef KWM_HINTS
  1065.     wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
  1066.     wKWMSendEventMessage(wwin, WKWMChangedClient);
  1067. #endif
  1068.  
  1069.     UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
  1070. }
  1071.  
  1072.  
  1073.  
  1074.  
  1075. void
  1076. wDeiconifyWindow(WWindow  *wwin)
  1077. {
  1078.     wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
  1079.  
  1080.     if (!wwin->flags.miniaturized)
  1081.     return;
  1082.  
  1083.     if (wwin->transient_for != None 
  1084.     && wwin->transient_for != wwin->screen_ptr->root_win) {
  1085.     WWindow *owner = recursiveTransientFor(wwin);
  1086.  
  1087.     if (owner && owner->flags.miniaturized) {
  1088.         wDeiconifyWindow(owner);
  1089.         wSetFocusTo(wwin->screen_ptr, wwin);
  1090.         wRaiseFrame(wwin->frame->core);
  1091.         return;
  1092.     }
  1093.     }
  1094.  
  1095.     wwin->flags.miniaturized = 0;
  1096.     if (!wwin->flags.shaded)
  1097.     wwin->flags.mapped = 1;
  1098.  
  1099.     if (!wPreferences.disable_miniwindows) {
  1100.     if (wwin->icon->selected)
  1101.         wIconSelect(wwin->icon);
  1102.  
  1103.     XUnmapWindow(dpy, wwin->icon->core->window);
  1104.     }
  1105.  
  1106. #ifdef WMSOUND
  1107.     wSoundPlay(WMSOUND_DEICONIFY);
  1108. #endif
  1109.  
  1110.     /* if the window is in another workspace, do it silently */
  1111. #ifdef ANIMATIONS
  1112.     if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations
  1113.     && !wwin->flags.skip_next_animation) {
  1114.     int ix, iy, iw, ih;
  1115.  
  1116.     if (!wPreferences.disable_miniwindows) {
  1117.         ix = wwin->icon_x;
  1118.         iy = wwin->icon_y;
  1119.         iw = wwin->icon->core->width;
  1120.         ih = wwin->icon->core->height;
  1121.     } else {
  1122. #ifdef KWM_HINTS
  1123.         WArea area;
  1124.  
  1125.         if (wKWMGetIconGeometry(wwin, &area)) {
  1126.         ix = area.x1;
  1127.         iy = area.y1;
  1128.         iw = area.x2 - ix;
  1129.         ih = area.y2 - iy;
  1130.         } else
  1131. #endif /* KWM_HINTS */
  1132.         {
  1133.         ix = 0;
  1134.         iy = 0;
  1135.         iw = wwin->screen_ptr->scr_width;
  1136.         ih = wwin->screen_ptr->scr_height;
  1137.         }
  1138.     }
  1139.     animateResize(wwin->screen_ptr, ix, iy, iw, ih,
  1140.               wwin->frame_x, wwin->frame_y,
  1141.               wwin->frame->core->width, wwin->frame->core->height,
  1142.               False);
  1143.     }
  1144. #endif /* ANIMATIONS */
  1145.     wwin->flags.skip_next_animation = 0;
  1146.     XGrabServer(dpy);
  1147.     if (!wwin->flags.shaded) {
  1148.     XMapWindow(dpy, wwin->client_win);
  1149.     }
  1150.     XMapWindow(dpy, wwin->frame->core->window);
  1151.     wRaiseFrame(wwin->frame->core);
  1152.     if (!wwin->flags.shaded) {
  1153.     wClientSetState(wwin, NormalState, None);
  1154.     }
  1155.     mapTransientsFor(wwin);
  1156.  
  1157.     if (!wPreferences.disable_miniwindows) {
  1158.     RemoveFromStackList(wwin->icon->core);
  1159.     /*    removeIconGrabs(wwin->icon);*/
  1160.     wIconDestroy(wwin->icon);
  1161.     wwin->icon = NULL;
  1162.     }
  1163.     XUngrabServer(dpy);
  1164.  
  1165.     if (wPreferences.focus_mode==WKF_CLICK)
  1166.     wSetFocusTo(wwin->screen_ptr, wwin);
  1167.  
  1168. #ifdef ANIMATIONS
  1169.     if (!wwin->screen_ptr->flags.startup) {
  1170.     Window clientwin = wwin->client_win;
  1171.     
  1172.         XSync(dpy, 0);
  1173.         processEvents(XPending(dpy));
  1174.     
  1175.     if (!wWindowFor(clientwin))
  1176.         return;
  1177.     }
  1178. #endif
  1179.     
  1180.     if (wPreferences.auto_arrange_icons) {
  1181.         wArrangeIcons(wwin->screen_ptr, True);
  1182.     }
  1183.  
  1184. #ifdef GNOME_STUFF
  1185.     wGNOMEUpdateClientStateHint(wwin, False);
  1186. #endif
  1187. #ifdef KWM_HINTS
  1188.     wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
  1189.     wKWMSendEventMessage(wwin, WKWMChangedClient);
  1190. #endif
  1191.  
  1192.     UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
  1193. }
  1194.  
  1195.  
  1196.  
  1197. static void
  1198. hideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate)
  1199. {
  1200.     if (wwin->flags.miniaturized) {
  1201.     if (wwin->icon) { 
  1202.         XUnmapWindow(dpy, wwin->icon->core->window);
  1203.         wwin->icon->mapped = 0;
  1204.     }
  1205.     wwin->flags.hidden = 1;
  1206. #ifdef GNOME_STUFF
  1207.     wGNOMEUpdateClientStateHint(wwin, False);
  1208. #endif
  1209.  
  1210.     UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
  1211.  
  1212.     return;
  1213.     }
  1214.  
  1215.     if (wwin->flags.inspector_open) {
  1216.     wHideInspectorForWindow(wwin);
  1217.     }
  1218.  
  1219.     wwin->flags.hidden = 1;
  1220.     wWindowUnmap(wwin);
  1221.  
  1222.     wClientSetState(wwin, IconicState, icon->icon_win);
  1223.     flushExpose();
  1224. #ifdef WMSOUND
  1225.     wSoundPlay(WMSOUND_HIDE);
  1226. #endif
  1227. #ifdef ANIMATIONS
  1228.     if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations &&
  1229.     !wwin->flags.skip_next_animation && animate) {
  1230.     animateResize(wwin->screen_ptr, wwin->frame_x, wwin->frame_y, 
  1231.               wwin->frame->core->width, wwin->frame->core->height,
  1232.               icon_x, icon_y, icon->core->width, icon->core->height,
  1233.               True);
  1234.     }
  1235. #endif
  1236.     wwin->flags.skip_next_animation = 0;
  1237.  
  1238. #ifdef GNOME_STUFF
  1239.     wGNOMEUpdateClientStateHint(wwin, False);
  1240. #endif
  1241.  
  1242.     UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
  1243. }
  1244.  
  1245.  
  1246.  
  1247. void
  1248. wHideOtherApplications(WWindow *awin)
  1249. {
  1250.     WWindow *wwin;
  1251.     WApplication *tapp;
  1252. #ifdef REDUCE_APPICONS
  1253.     char *tinstance, *tclass;
  1254.     unsigned int brokenwin = 0, match = 0;
  1255. #endif
  1256.  
  1257.     if (!awin)
  1258.     return;
  1259.     wwin = awin->screen_ptr->focused_window;
  1260.  
  1261. #ifdef REDUCE_APPICONS
  1262.     if (awin->wm_instance == NULL || awin->wm_class == NULL)
  1263.     brokenwin++;
  1264. #endif
  1265.  
  1266.     while (wwin) {
  1267.     if (wwin!=awin 
  1268.         && wwin->frame->workspace == awin->screen_ptr->current_workspace
  1269.             && !(wwin->flags.miniaturized||wwin->flags.hidden)
  1270.             && !wwin->flags.internal_window
  1271.         && wGetWindowOfInspectorForWindow(wwin) != awin
  1272.         && !WFLAGP(wwin, no_hide_others)) {
  1273.         
  1274. #ifdef REDUCE_APPICONS
  1275.         match = 0;
  1276.         if (!brokenwin) {
  1277.         if ((tinstance = wwin->wm_instance) == NULL)
  1278.             tinstance = "";
  1279.         if ((tclass = wwin->wm_class) == NULL)
  1280.             tclass = "";
  1281.         if ((strcmp(awin->wm_instance, tinstance) == 0) &&
  1282.             (strcmp(awin->wm_class, tclass) == 0) )
  1283.             match++;
  1284.         }
  1285. #endif
  1286.  
  1287.         if (wwin->main_window==None || WFLAGP(wwin, no_appicon)) {
  1288.         if (!WFLAGP(wwin, no_miniaturizable)) {
  1289.             wwin->flags.skip_next_animation = 1;
  1290.             wIconifyWindow(wwin);
  1291.         }
  1292.         } else if (wwin->main_window!=None
  1293. #ifndef REDUCE_APPICONS
  1294.                && awin->main_window != wwin->main_window) {
  1295. #else
  1296.             && (awin->main_window != wwin->main_window && !match)) {
  1297. #endif
  1298.         tapp = wApplicationOf(wwin->main_window);
  1299.         if (tapp) {
  1300.             tapp->flags.skip_next_animation = 1;
  1301.             wHideApplication(tapp);
  1302.         } else {
  1303.             if (!WFLAGP(wwin, no_miniaturizable)) {
  1304.                 wwin->flags.skip_next_animation = 1;
  1305.                 wIconifyWindow(wwin);
  1306.             }
  1307.         }
  1308.         }
  1309.     }
  1310.     wwin = wwin->prev;
  1311.     }
  1312.     /*
  1313.     wSetFocusTo(awin->screen_ptr, awin);
  1314.      */
  1315. }
  1316.  
  1317.  
  1318.  
  1319. void
  1320. wHideApplication(WApplication *wapp)
  1321. {
  1322. #ifdef REDUCE_APPICONS
  1323.     WApplication *tapp;
  1324.     char *tinstance, *tclass;
  1325.     unsigned int nowmhints = 0, matchwmhints = 0, matchworkspace = 0;
  1326. #endif
  1327.     WScreen *scr;
  1328.     WWindow *wlist;
  1329.     int hadfocus;
  1330.     
  1331.     if (!wapp) {
  1332.     wwarning("trying to hide a non grouped window");
  1333.     return;
  1334.     }
  1335.     if (!wapp->main_window_desc) {
  1336.     wwarning("group leader not found for window group");
  1337.     return;
  1338.     }
  1339. #ifdef REDUCE_APPICONS
  1340.     if ((wapp->main_window_desc->wm_instance == NULL) ||
  1341.         (wapp->main_window_desc->wm_class == NULL))
  1342.         nowmhints++;
  1343. #endif
  1344.     scr = wapp->main_window_desc->screen_ptr;
  1345.     hadfocus = 0;
  1346.     wlist = scr->focused_window;
  1347.     if (!wlist)
  1348.     return;
  1349.  
  1350.     if (wlist->main_window == wapp->main_window)
  1351.     wapp->last_focused = wlist;
  1352.     else
  1353.     wapp->last_focused = NULL;
  1354.     while (wlist) {
  1355. #ifdef REDUCE_APPICONS
  1356.     matchwmhints = matchworkspace = 0;
  1357.     if (!nowmhints) {
  1358.         tapp = wApplicationOf(wlist->main_window);
  1359.         tinstance = tclass = NULL;
  1360.         if (tapp) {
  1361.         if (tapp->main_window_desc) {
  1362.             tinstance = tapp->main_window_desc->wm_instance;
  1363.             tclass = tapp->main_window_desc->wm_class;
  1364.         }
  1365.         }
  1366.         if (tapp == NULL || tinstance == NULL || tclass == NULL) {
  1367.         /* Should never reach here */
  1368.         tinstance = "";
  1369.         tclass = "";
  1370.         }
  1371.         if ((strcmp(tinstance, wapp->main_window_desc->wm_instance) == 0) &&
  1372.         (strcmp(tclass, wapp->main_window_desc->wm_class) == 0) )
  1373.         matchwmhints++;
  1374.     }
  1375.     if (wlist->frame) {
  1376.         if (wlist->frame->workspace == wapp->main_window_desc->screen_ptr->current_workspace)
  1377.         matchworkspace++;
  1378.     }
  1379.         if ((wlist->main_window == wapp->main_window || matchwmhints) && 
  1380.         matchworkspace) {
  1381. #ifdef I_HATE_THIS
  1382.     }
  1383. #endif
  1384. #else
  1385.     if (wlist->main_window == wapp->main_window) {
  1386. #endif
  1387.         if (wlist->flags.focused) {
  1388.         hadfocus = 1;
  1389.             }
  1390.             if (wapp->app_icon)
  1391.                 hideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
  1392.                            wapp->app_icon->y_pos, wlist,
  1393.                            !wapp->flags.skip_next_animation);
  1394.     }
  1395.     wlist = wlist->prev;
  1396.     }
  1397.     
  1398.     wapp->flags.skip_next_animation = 0;    
  1399.  
  1400.     if (hadfocus) {
  1401.     if (wPreferences.focus_mode==WKF_CLICK) {
  1402.         wlist = scr->focused_window;
  1403.         while (wlist) {
  1404.         if (!WFLAGP(wlist, no_focusable) && !wlist->flags.hidden
  1405.             && (wlist->flags.mapped || wlist->flags.shaded))
  1406.           break;
  1407.         wlist = wlist->prev;
  1408.         }
  1409.         wSetFocusTo(scr, wlist);
  1410.     } else {
  1411.         wSetFocusTo(scr, NULL);
  1412.     }
  1413.     }
  1414.     
  1415.     wapp->flags.hidden = 1;
  1416.     
  1417.     if(wPreferences.auto_arrange_icons) {
  1418.     wArrangeIcons(scr, True);
  1419.     }
  1420. #ifdef HIDDENDOT
  1421.     if (wapp->app_icon)
  1422.         wAppIconPaint(wapp->app_icon);
  1423. #endif
  1424. }
  1425.  
  1426.  
  1427.  
  1428.  
  1429. static void
  1430. unhideWindow(WIcon *icon, int icon_x, int icon_y, WWindow *wwin, int animate,
  1431.          int bringToCurrentWS)
  1432. {
  1433.     if (bringToCurrentWS)
  1434.     wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace);
  1435.  
  1436.     wwin->flags.hidden=0;
  1437.     wwin->flags.mapped=1;
  1438.     
  1439. #ifdef WMSOUND
  1440.     wSoundPlay(WMSOUND_UNHIDE);
  1441. #endif
  1442. #ifdef ANIMATIONS
  1443.     if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations 
  1444.     && animate) {
  1445.     animateResize(wwin->screen_ptr, icon_x, icon_y,
  1446.               icon->core->width, icon->core->height,
  1447.               wwin->frame_x, wwin->frame_y, 
  1448.               wwin->frame->core->width, wwin->frame->core->height,
  1449.                       True);
  1450.     }
  1451. #endif
  1452.     wwin->flags.skip_next_animation = 0;
  1453.     XMapWindow(dpy, wwin->client_win);
  1454.     XMapWindow(dpy, wwin->frame->core->window);
  1455.     wClientSetState(wwin, NormalState, None);
  1456.     wRaiseFrame(wwin->frame->core);
  1457.     if (wwin->flags.inspector_open) {
  1458.     wUnhideInspectorForWindow(wwin);
  1459.     }
  1460.  
  1461. #ifdef GNOME_STUFF
  1462.     wGNOMEUpdateClientStateHint(wwin, False);
  1463. #endif
  1464.  
  1465.     UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
  1466.  
  1467. }
  1468.  
  1469.  
  1470. void
  1471. wUnhideApplication(WApplication *wapp, Bool miniwindows, Bool bringToCurrentWS)
  1472. {
  1473.     WScreen *scr;
  1474.     WWindow *wlist, *next;
  1475.     WWindow *focused=NULL;
  1476. #ifdef REDUCE_APPICONS
  1477.     char *tinstance, *tclass;
  1478.     unsigned int nowmhints = 0, matchwmhints = 0, matchworkspace = 0;
  1479. #endif
  1480.  
  1481.     if (!wapp) {
  1482.     return;
  1483.     }
  1484.  
  1485. #ifdef REDUCE_APPICONS
  1486.     if ((wapp->main_window_desc->wm_class == NULL) || 
  1487.     (wapp->main_window_desc->wm_instance == NULL))
  1488.     nowmhints++;
  1489. #endif
  1490.  
  1491.     scr = wapp->main_window_desc->screen_ptr;
  1492.     wlist = scr->focused_window;
  1493.     if (!wlist) return;
  1494.     /* goto beginning of list */
  1495.     while (wlist->prev)
  1496.       wlist = wlist->prev;
  1497.     
  1498.     while (wlist) {
  1499.     next = wlist->next;
  1500.  
  1501. #ifndef REDUCE_APPICONS    
  1502.     if (wlist->main_window == wapp->main_window) {
  1503. #else
  1504.     matchwmhints = matchworkspace = 0;
  1505.     if (!nowmhints) {
  1506.         if ((tinstance = wlist->wm_instance) == NULL)
  1507.         tinstance = "";
  1508.         if ((tclass = wlist->wm_class) == NULL)
  1509.         tclass = "";
  1510.         if ((strcmp(tinstance, wapp->main_window_desc->wm_instance) == 0) 
  1511.         && (strcmp(tclass, wapp->main_window_desc->wm_class) == 0) )
  1512.         matchwmhints++;
  1513.     }
  1514.     if (wlist->frame) {
  1515.         if (wlist->frame->workspace == wapp->main_window_desc->screen_ptr->current_workspace)
  1516.         matchworkspace++;
  1517.     }
  1518.  
  1519.     if ((wlist->main_window == wapp->main_window || matchwmhints) && 
  1520.         matchworkspace) {
  1521. #endif
  1522.         if (wlist->flags.focused)
  1523.           focused = wlist;
  1524.         else if (!focused || !focused->flags.focused)
  1525.           focused = wlist;
  1526.         
  1527.         if (wlist->flags.miniaturized && wlist->icon) {
  1528.                 if (bringToCurrentWS || wPreferences.sticky_icons
  1529.             || wlist->frame->workspace == scr->current_workspace) {
  1530.             if (!wlist->icon->mapped) {
  1531.             XMapWindow(dpy, wlist->icon->core->window);
  1532.             wlist->icon->mapped = 1;
  1533.             }
  1534.             wlist->flags.hidden = 0;
  1535.  
  1536.             UpdateSwitchMenu(scr, wlist, ACTION_CHANGE_STATE);
  1537.  
  1538.             if (wlist->frame->workspace != scr->current_workspace)
  1539.             wWindowChangeWorkspace(wlist, scr->current_workspace);
  1540.         }
  1541.         if (miniwindows) {
  1542.             wDeiconifyWindow(wlist);
  1543.         }
  1544.         } else if (wlist->flags.hidden) {
  1545.         unhideWindow(wapp->app_icon->icon, wapp->app_icon->x_pos,
  1546.                  wapp->app_icon->y_pos, wlist, 
  1547.                  !wapp->flags.skip_next_animation,
  1548.                  bringToCurrentWS);
  1549.         } else {
  1550.         if (bringToCurrentWS
  1551.             && wlist->frame->workspace != scr->current_workspace) {
  1552.             wWindowChangeWorkspace(wlist, scr->current_workspace);
  1553.         }
  1554.         wRaiseFrame(wlist->frame->core);
  1555.         }
  1556.     }
  1557.     wlist = next;
  1558.     }
  1559.     
  1560.     wapp->flags.skip_next_animation = 0;
  1561.     wapp->flags.hidden = 0;
  1562.     
  1563.     if (focused)
  1564.     wSetFocusTo(scr, focused);
  1565.     else if (wapp->last_focused && wapp->last_focused->flags.mapped)
  1566.     wSetFocusTo(scr, wapp->last_focused);
  1567.     wapp->last_focused = NULL;
  1568.     if (wPreferences.auto_arrange_icons) {
  1569.         wArrangeIcons(scr, True);
  1570.     }
  1571. #ifdef HIDDENDOT
  1572.     wAppIconPaint(wapp->app_icon);
  1573. #endif 
  1574. }
  1575.  
  1576.  
  1577.  
  1578. void
  1579. wShowAllWindows(WScreen *scr)
  1580. {
  1581.     WWindow *wwin, *old_foc;
  1582.     WApplication *wapp;
  1583.  
  1584.     old_foc = wwin = scr->focused_window;
  1585.     while (wwin) {
  1586.         if (!wwin->flags.internal_window &&
  1587.             (scr->current_workspace == wwin->frame->workspace
  1588.         || IS_OMNIPRESENT(wwin))) {
  1589.         if (wwin->flags.miniaturized) {
  1590.         wwin->flags.skip_next_animation = 1;
  1591.         wDeiconifyWindow(wwin);
  1592.         } else if (wwin->flags.hidden) {
  1593.         wapp = wApplicationOf(wwin->main_window);
  1594.         if (wapp) {
  1595.             wUnhideApplication(wapp, False, False);
  1596.         } else {
  1597.             wwin->flags.skip_next_animation = 1;
  1598.             wDeiconifyWindow(wwin);
  1599.         }
  1600.         }
  1601.     }
  1602.     wwin = wwin->prev;
  1603.     }
  1604.     wSetFocusTo(scr, old_foc);
  1605.     /*wRaiseFrame(old_foc->frame->core);*/
  1606. }
  1607.  
  1608.  
  1609. void
  1610. wRefreshDesktop(WScreen *scr)
  1611. {
  1612.     Window win;
  1613.     XSetWindowAttributes attr;
  1614.  
  1615.     attr.backing_store = NotUseful;
  1616.     attr.save_under = False;
  1617.     win = XCreateWindow(dpy, scr->root_win, 0, 0, scr->scr_width, 
  1618.             scr->scr_height, 0, CopyFromParent, CopyFromParent,
  1619.             (Visual *)CopyFromParent, CWBackingStore|CWSaveUnder,
  1620.             &attr);
  1621.     XMapRaised(dpy, win);
  1622.     XDestroyWindow(dpy, win);
  1623.     XFlush(dpy);
  1624. }
  1625.  
  1626.  
  1627. void
  1628. wArrangeIcons(WScreen *scr, Bool arrangeAll)
  1629. {
  1630.     WWindow *wwin;
  1631.     WAppIcon *aicon;
  1632.     int pf;                   /* primary axis */
  1633.     int sf;                   /* secondary axis */
  1634.     int fullW;
  1635.     int fullH;
  1636.     int pi, si;
  1637.     int sx1, sx2, sy1, sy2;           /* screen boundary */
  1638.     int sw, sh;
  1639.     int xo, yo;
  1640.     int xs, ys;
  1641.     int isize = wPreferences.icon_size;
  1642.  
  1643.     /*
  1644.      * Find out screen boundaries.
  1645.      */
  1646.     sx1 = 0;
  1647.     sy1 = 0;
  1648.     sx2 = scr->scr_width;
  1649.     sy2 = scr->scr_height;
  1650.     if (scr->dock) {
  1651.     if (scr->dock->on_right_side)
  1652.             sx2 -= isize + DOCK_EXTRA_SPACE;
  1653.     else
  1654.         sx1 += isize + DOCK_EXTRA_SPACE;
  1655.     }
  1656.  
  1657.     sw = isize * (scr->scr_width/isize);
  1658.     sh = isize * (scr->scr_height/isize);
  1659.     fullW = (sx2-sx1)/isize;
  1660.     fullH = (sy2-sy1)/isize;
  1661.  
  1662.     /* icon yard boundaries */    
  1663.     if (wPreferences.icon_yard & IY_VERT) {
  1664.     pf = fullH;
  1665.     sf = fullW;
  1666.     } else {
  1667.     pf = fullW;
  1668.     sf = fullH;
  1669.     }
  1670.     if (wPreferences.icon_yard & IY_RIGHT) {
  1671.     xo = sx2 - isize;
  1672.     xs = -1;
  1673.     } else {
  1674.     xo = sx1;
  1675.     xs = 1;
  1676.     }
  1677.     if (wPreferences.icon_yard & IY_TOP) {
  1678.     yo = sy1;
  1679.     ys = 1;
  1680.     } else {
  1681.     yo = sy2 - isize;
  1682.     ys = -1;
  1683.     }
  1684.  
  1685.     /* arrange icons putting the most recently focused window
  1686.      * as the last icon */
  1687. #define X ((wPreferences.icon_yard & IY_VERT) ? xo + xs*(si*isize)\
  1688.             : xo + xs*(pi*isize))
  1689. #define Y ((wPreferences.icon_yard & IY_VERT) ? yo + ys*(pi*isize)\
  1690.             : yo + ys*(si*isize))
  1691.  
  1692.     /* arrange application icons */
  1693.     aicon = scr->app_icon_list;
  1694.     /* reverse them to avoid unnecessarily sliding of icons */
  1695.     while (aicon && aicon->next)
  1696.         aicon = aicon->next;
  1697.  
  1698.     pi = 0;
  1699.     si = 0;
  1700.     while (aicon) {
  1701.         if (!aicon->docked) {
  1702.             if (aicon->x_pos != X || aicon->y_pos != Y) {
  1703. #ifdef ANIMATIONS
  1704.                 if (!wPreferences.no_animations) {
  1705.                     SlideWindow(aicon->icon->core->window, aicon->x_pos, aicon->y_pos,
  1706.                                 X, Y);
  1707.                 }
  1708. #endif /* ANIMATIONS */
  1709.             }
  1710.         wAppIconMove(aicon, X, Y);
  1711.             pi++;
  1712.         }
  1713.         /* we reversed the order so we use prev */
  1714.         aicon = aicon->prev;
  1715.         if (pi >= pf) {
  1716.             pi=0;
  1717.             si++;
  1718.         }
  1719.     }
  1720.     
  1721.     /* arrange miniwindows */
  1722.  
  1723.     wwin = scr->focused_window;
  1724.     /* reverse them to avoid unnecessarily shuffling */
  1725.     while (wwin && wwin->prev)
  1726.         wwin = wwin->prev;
  1727.  
  1728.     while (wwin) {
  1729.         if (wwin->icon && wwin->flags.miniaturized && !wwin->flags.hidden &&
  1730.             (wwin->frame->workspace==scr->current_workspace ||
  1731.              IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons)) {
  1732.         
  1733.         if (arrangeAll || !wwin->flags.icon_moved) {
  1734.         if (wwin->icon_x != X || wwin->icon_y != Y) {
  1735. #ifdef ANIMATIONS
  1736.             if (wPreferences.no_animations) {
  1737.             XMoveWindow(dpy, wwin->icon->core->window, X, Y);
  1738.             } else {
  1739.             SlideWindow(wwin->icon->core->window, wwin->icon_x, 
  1740.                     wwin->icon_y, X, Y);
  1741.             }
  1742. #else
  1743.             XMoveWindow(dpy, wwin->icon->core->window, X, Y);
  1744. #endif /* ANIMATIONS */
  1745.         }
  1746.         wwin->icon_x = X;
  1747.         wwin->icon_y = Y;
  1748.         pi++;
  1749.         }
  1750.     }
  1751.     if (arrangeAll) {
  1752.         wwin->flags.icon_moved = 0;
  1753.     }
  1754.         /* we reversed the order, so we use next */
  1755.         wwin = wwin->next;
  1756.     if (pi >= pf) {
  1757.         pi=0;
  1758.         si++;
  1759.     }
  1760.     }
  1761. }
  1762.  
  1763.  
  1764. void
  1765. wSelectWindow(WWindow *wwin, Bool flag)
  1766. {
  1767.     WScreen *scr = wwin->screen_ptr;
  1768.     
  1769.     if (flag) {
  1770.     wwin->flags.selected = 1;
  1771.     XSetWindowBorder(dpy, wwin->frame->core->window, scr->white_pixel);
  1772.     
  1773.     if (WFLAGP(wwin, no_border)) {    
  1774.         XSetWindowBorderWidth(dpy, wwin->frame->core->window, 
  1775.                   FRAME_BORDER_WIDTH);
  1776.     }
  1777.  
  1778.     if (!scr->selected_windows)
  1779.         scr->selected_windows = WMCreateBag(4);
  1780.     WMPutInBag(scr->selected_windows, wwin);
  1781.     } else {
  1782.     wwin->flags.selected = 0;
  1783.     XSetWindowBorder(dpy, wwin->frame->core->window,
  1784.              scr->frame_border_pixel);
  1785.  
  1786.     if (WFLAGP(wwin, no_border)) {    
  1787.         XSetWindowBorderWidth(dpy, wwin->frame->core->window, 0);
  1788.     }
  1789.  
  1790.     if (scr->selected_windows) {
  1791.         WMRemoveFromBag(scr->selected_windows, wwin);
  1792.     }
  1793.     }
  1794. }
  1795.  
  1796.  
  1797. void
  1798. wMakeWindowVisible(WWindow *wwin)
  1799. {
  1800.     if (wwin->frame->workspace != wwin->screen_ptr->current_workspace)
  1801.     wWorkspaceChange(wwin->screen_ptr, wwin->frame->workspace);
  1802.  
  1803.     if (wwin->flags.shaded) {
  1804.     wUnshadeWindow(wwin);
  1805.     }
  1806.     if (wwin->flags.hidden) {
  1807.     WApplication *app;
  1808.  
  1809.     app = wApplicationOf(wwin->main_window);
  1810.     if (app)
  1811.         wUnhideApplication(app, False, False);
  1812.     } else if (wwin->flags.miniaturized) {
  1813.     wDeiconifyWindow(wwin);
  1814.     } else {
  1815.     if (!WFLAGP(wwin, no_focusable))
  1816.         wSetFocusTo(wwin->screen_ptr, wwin);
  1817.     wRaiseFrame(wwin->frame->core);
  1818.     }
  1819. }
  1820.